package com.jiandan.asm

//import com.jiandan.annotation.FastClick
//import org.objectweb.asm.Type
import org.objectweb.asm.AnnotationVisitor

import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.commons.AdviceAdapter

/**
 * 防止快速点击
 */
class ASMMethodAdapter extends AdviceAdapter {


    //标记 当前方法是否需要计算耗时
    private boolean traceFastClick
    private boolean traceMethodTime
    private int timeLocalIndex
    FastClickAnnotationVisitor activityAnnotationVisitor = null

    private String className // 不包含包名的类名
    private String fullMethodName// 包含包名、类名、参数名、的方法名字
    private String methodName// 不包含包名名类名的方法名字

    ASMMethodAdapter(int api, MethodVisitor methodVisitor, int access, String name, String descriptor, String className) {
        super(api, methodVisitor, access, name, descriptor)
        this.methodName = name
        this.fullMethodName = className + name + descriptor
        String[] path = className.split("/")
        this.className = path[path.length - 1]
    }

    @Override
    AnnotationVisitor visitAnnotation(String desc, boolean visible) {
        AnnotationVisitor annotationVisitor = super.visitAnnotation(desc, visible);
        //方法上面的注解 如果和FastClick一样
        //if (Type.getDescriptor(FastClick.class) == desc) {
        if ("Lcom/jiandan/annotation/FastClick;" == desc) {
            println("handle FastClick : $fullMethodName")
            traceFastClick = true
            activityAnnotationVisitor = new FastClickAnnotationVisitor(Opcodes.ASM5, annotationVisitor, fullMethodName)
            return activityAnnotationVisitor
        }
        if ("Lcom/jiandan/annotation/MethodTime;" == desc) {
            println("handle MethodTime : $fullMethodName")
            traceMethodTime = true
            return annotationVisitor
        }
        return annotationVisitor
    }
    //方法进入
    @Override
    protected void onMethodEnter() {
        super.onMethodEnter()
        if (traceFastClick) {
            mv.visitLdcInsn(activityAnnotationVisitor.fullMethodName)
            mv.visitLdcInsn(activityAnnotationVisitor.value)
            mv.visitMethodInsn(INVOKESTATIC, "com/jiandan/aspect/FastClickUtil", "isFastDoubleClick", "(Ljava/lang/String;J)Z", false)
            Label label = new Label()
            mv.visitJumpInsn(IFEQ, label)//true 跳出方法
            mv.visitInsn(RETURN)
            mv.visitLabel(label)
        } else if (traceMethodTime) {
            //构造一个局部变量
            timeLocalIndex = newLocal(Type.LONG_TYPE)
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false)
            mv.visitVarInsn(LSTORE, timeLocalIndex)
        }

    }

    //方法结束
    @Override
    protected void onMethodExit(int opcode) {
        super.onMethodExit(opcode)
        if (traceMethodTime) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false)
            mv.visitVarInsn(LLOAD, timeLocalIndex)
            mv.visitInsn(LSUB)
            mv.visitVarInsn(LSTORE, timeLocalIndex)
            mv.visitLdcInsn(className)
            mv.visitTypeInsn(NEW, "java/lang/StringBuilder")
            mv.visitInsn(DUP)
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false)
            mv.visitLdcInsn(methodName + " useTime ")
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false)
            mv.visitVarInsn(LLOAD, timeLocalIndex)
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;", false)
            mv.visitLdcInsn("ms")
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false)
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false)
            mv.visitMethodInsn(INVOKESTATIC, "android/util/Log", "d", "(Ljava/lang/String;Ljava/lang/String;)I", false)
            mv.visitInsn(POP)
        }
    }

}